#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <mysql.h>

#define	SHA1SIZE 20
#define	HEXSIZE	(2*SHA1SIZE)
#define	CHUNKSIZE 16384

#define	MYSQL_INSERT_QUERY \
	"INSERT INTO store (sha1,size,data) VALUES ('%s',%d,'%s')"
#define	MYSQL_INSERT_SIZE \
	(sizeof(MYSQL_INSERT_QUERY) + HEXSIZE + 2*CHUNKSIZE + 1)

char host[256] = "localhost";
int port = 0;
char database[256] = "entropy";
char user[256] = "myname";
char pass[256] = "mypass";
int unlink_files = 0;

MYSQL *mysql;

int insert(char *filename)
{
	static char query[MYSQL_INSERT_SIZE];
	static char chunk[2*CHUNKSIZE+1];
	static u_int8_t data[CHUNKSIZE];
	char *sha1;
	int len, size;
	FILE *fp;

	fp = fopen(filename, "rb");
	if (NULL == fp) {
		fprintf(stderr, "error reading '%s' (%s)\n",
			filename, strerror(errno));
		return -1;
	}
	size = fread(data, 1, CHUNKSIZE, fp);
	if (size < 0) {
		fprintf(stderr, "error reading '%s' (%s)\n",
			filename, strerror(errno));
		return -1;
	}
	fclose(fp);
	sha1 = strrchr(filename, '/');
	sha1 = (NULL == sha1) ? filename : sha1 + 1;
	mysql_real_escape_string(mysql, chunk, data, size);

	len = snprintf(query, MYSQL_INSERT_SIZE, MYSQL_INSERT_QUERY,
		sha1, size, chunk);
	if (0 != mysql_real_query(mysql, query, len)) {
		if (1062 != mysql_errno(mysql)) {
			fprintf(stderr, "error executing '%s' (%s)\n",
				filename, mysql_error(mysql));
			return -1;
		}
		/* ignore duplicate keys */
	}
	if (0 != unlink_files) {
		unlink(filename);
	}
	printf("%5d %5d %s\n", size, len, filename);
	return 0;
}

int main(int ac, char **av)
{
	char path[256];
	char line[256], *eol;
	DIR *dir;
	struct dirent *de;
	int i, cwd;
	FILE *fp;

	cwd = open(".", O_RDONLY);
	if (-1 == cwd) {
		fprintf(stderr, "open('.', O_RDONLY) failed (%s)\n",
			strerror(errno));
		exit(1);
	}

	fp = fopen("entropy.conf", "r");
	if (NULL != fp) {
		while (!feof(fp)) {
			if (NULL == fgets(line, sizeof(line), fp))
				break;
			eol = strchr(line, '\n');
			if (NULL != eol) *eol = '\0';
			eol = strchr(line, '\r');
			if (NULL != eol) *eol = '\0';
			if (0 == strncmp(line, "mysql_user=", 11)) {
				strcpy(user, line + 11);
			} else if (0 == strncmp(line, "mysql_pass=", 11)) {
				strcpy(pass, line + 11);
			} else if (0 == strncmp(line, "mysql_db=", 9)) {
				strcpy(database, line + 9);
			} else if (0 == strncmp(line, "mysql_host=", 11)) {
				strcpy(host, line + 11);
			} else if (0 == strncmp(line, "mysql_port=", 11)) {
				port = atoi(line + 11);
			}
		}
	}
	for (i = 1; i < ac; i++) {
		if (0 == strcmp(av[i], "-u") || 0 == strcmp(av[i], "--unlink"))
			unlink_files = 1;
	}
	printf("Connecting to %s:%d database %s as %s pass %-*.*s\n",
		host, port, database, user,
		strlen(pass), strlen(pass),
		"****************************************");

	mysql = mysql_init(NULL);
	if (NULL ==  mysql) {
		fprintf(stderr, "mysql_init failed (out of memory)\n");
		exit(1);
	}

	while (NULL == mysql_real_connect(mysql, host, user, pass, database, port, NULL, 0)) {
		printf("connection failed (%s)\n", mysql_error(mysql));
		sleep(3);
	}

	for (i = 0; i < 16; i++) {
		sprintf(path, "store/%x", i);
		if (0 != chdir(path)) {
			printf("chdir(%s) failed (%s)\n",
				path, strerror(errno));
			continue;
		}
		dir = opendir(".");
		if (NULL != dir) {
			while (NULL != (de = readdir(dir))) {
				if (0 == strcmp(de->d_name, ".") ||
					0 == strcmp(de->d_name, ".."))
					continue;
				if (HEXSIZE != strlen(de->d_name)) {
					printf("ignoring %s\n", de->d_name);
				} else if (0 != insert(de->d_name)) {
					exit(1);
				}
			}
			closedir(dir);
		}
		fchdir(cwd);
	}

	return 0;
}
